#include "FindFilter.h"
#include "common.h"

#include <streams.h>

HRESULT FindVideoCompressor(const std::wstring& format, IBaseFilter *&result)
{
	HRESULT hr = S_OK;

	CoInitialize(NULL);
	ComUninitial comUninitial;

	ICreateDevEnum *createDevEnum;
	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&createDevEnum);
	if(FAILED(hr))
	{
		ErrorPrint("Create system device enum error", hr);
		return hr;
	}
	ComReleaser createDevEnumReleaser(createDevEnum);

	IEnumMoniker *enumMoniker;
	hr = createDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &enumMoniker, 0);
	if (FAILED(hr))
	{
		ErrorPrint("Create Video compressor enum error", hr);
		return hr;
	}

	IMoniker *moniker;
	while(S_OK == enumMoniker->Next(1, &moniker, NULL))
	{
		ComReleaser monikerReleaser(moniker);
		
		LPOLESTR oleDisplayName;
		hr = moniker->GetDisplayName(NULL, NULL, &oleDisplayName);
		if(FAILED(hr))
		{
			ErrorPrint("Get display name error", hr);
			continue;
		}
		std::wstring displayName(oleDisplayName);

		size_t slashPos;
		for (slashPos = 0; slashPos < displayName.size(); ++slashPos)
		{
			if(displayName[slashPos] == L'\\')
				break;
		}
		if(slashPos == displayName.size())
		{
			ErrorPrint("Find slash error");
			continue;
		}

		displayName = displayName.substr(slashPos+1);
		if (displayName == format)
		{
			hr = moniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&result);
			if(FAILED(hr))
			{
				ErrorPrint("Create video compressor filter error", hr);
				continue;
			}
			return S_OK;
		}

	}

	return E_FAIL;
}

HRESULT GetFreePin(IBaseFilter* filter, IPin*& result, PIN_DIRECTION dir)
{
	HRESULT hr = S_OK;
	IEnumPins *enumPins;
	hr = filter->EnumPins(&enumPins);
	if(FAILED(hr))
	{
		ErrorPrint("Enum pins error");
		return hr;
	}
	ComReleaser enumPinsReleaser(enumPins);

	IPin *pin;
	while (S_OK == enumPins->Next(1, &pin, NULL))
	{
		PIN_INFO pinInfo;
		hr = pin->QueryPinInfo(&pinInfo);
		if(FAILED(hr))
		{
			ErrorPrint("Query pin info error");
			pin->Release();
			continue;
		}
		if(pinInfo.dir == dir)
		{
			IPin* connectedPin;
			pin->ConnectedTo(&connectedPin);
			if(connectedPin == NULL)
			{
				result = pin;
				return S_OK;
			}
		}
		pin->Release();

	}

	return E_FAIL;
}